package cn.demomaster.quickui.view.banner;


import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.view.NestedScrollingChild;
import androidx.core.view.NestedScrollingChild2;
import androidx.core.view.NestedScrollingChild3;
import androidx.core.view.NestedScrollingChildHelper;
import androidx.core.view.NestedScrollingParent;
import androidx.core.view.NestedScrollingParent2;
import androidx.core.view.NestedScrollingParent3;
import androidx.core.view.NestedScrollingParentHelper;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;

import com.demomaster.quickcompat.util.DisplayUtil;
import com.demomaster.quickcompat.widget.layout.QuickFrameLayout;

import java.util.ArrayList;
import java.util.List;

import cn.demomaster.quicklogger.QdLog;

public class Banner extends QuickFrameLayout implements NestedScrollingParent3, NestedScrollingChild3, NestedScrollingParent2, NestedScrollingParent, NestedScrollingChild, NestedScrollingChild2 {
    private static String TAG = Banner.class.getSimpleName();

    public Banner(@NonNull Context context) {
        super(context);
        init();
    }

    public Banner(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public Banner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    ViewPager2 mViewPager;
    BannerIndicator mBannerCursorView;//游标指示器控件

    /**
     * 指示器的样式
     */
    public enum IndicatorStyle {
        None,
        Circle,
        Rectangle,
        Custom
    }

    int direction = LinearLayout.HORIZONTAL;//LinearLayout.VERTICAL;

    /**
     * 设置banner 方向和滚动动画
     *
     * @param direction
     */
    public void setDirection(int direction) {
        this.direction = direction;
        setOrientation(direction);
        if (direction == LinearLayout.HORIZONTAL) {
            //setPageTransformer(true,new ZoomOutPageTransformer2());
        } else {
            setPageTransformer(true, new ZoomOutPageTransformer());
        }
    }

    /**
     * 设置滚动器样式
     *
     * @param indicatorStyle
     */
    public void setIndicatorStyle(IndicatorStyle indicatorStyle) {
        switch (indicatorStyle) {
            case None:
                setIndicatorView(null);
                break;
            case Circle:
                setIndicatorView(new BannerCursorView(getContext()));
                break;
            case Rectangle:
                setIndicatorView(new BannerCursorView2(getContext()));
                break;
            case Custom:
                setIndicatorView(mBannerCursorView);
                break;
        }
    }

    int selectIndex = 0;
    int indicatorCount = 0;

    /**
     * 设置轮播滚动器
     *
     * @param bannerCursorView
     */
    public void setIndicatorView(BannerIndicator bannerCursorView) {
        if (mBannerCursorView == bannerCursorView) {
            return;
        }
        if (mBannerCursorView instanceof View && ((View) mBannerCursorView).getParent() != null) {
            removeView((View) mBannerCursorView);
            mBannerCursorView = null;
        }
        if (bannerCursorView instanceof View) {
            if (((View) bannerCursorView).getParent() == null) {
                LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 80);
                layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER;
                addView((View) bannerCursorView, 1, layoutParams);
            }
        }
        mBannerCursorView = bannerCursorView;
        if (mBannerCursorView != null) {
            selectIndex = adsAdapter.getDataPosition(mViewPager.getCurrentItem());
            mBannerCursorView.selecte(selectIndex);
            mBannerCursorView.setIndicatorCount(indicatorCount);
        }
    }

    BannerFragmentStateAdapter adsAdapter;
    int currentPosition;
    FragmentHander fragmentHander;
    Class<? extends BannerFragment> claszz = BannerFragment2.class;

    public void setClaszz(Class<? extends BannerFragment> claszz) {
        this.claszz = claszz;
        adsAdapter = new BannerFragmentStateAdapter((FragmentActivity) getContext(), claszz, adsResourceList, fragmentHander, () -> setCurrentItem(mViewPager.getCurrentItem() + 1));
        mViewPager.setAdapter(adsAdapter);
        setCurrentItem(adsAdapter.firstFragmentPosition, false);
    }

    private final int[] mNestedScrollingV2ConsumedCompat = new int[2];
    NestedScrollingChildHelper mNestedScrollingChildHelper;
    private NestedScrollingParentHelper mNestedScrollingParentHelper;
    private int marginLeft = 0;
    private int marginRight = 0;

    public void setMargin(int marginLeft, int marginTop, int marginRight, int marginBottom) {
        this.marginLeft = marginLeft;
        this.marginRight = marginRight;
        LayoutParams layoutParams1 = (LayoutParams) mViewPager.getLayoutParams();
        layoutParams1.setMargins(marginLeft, layoutParams1.topMargin, marginRight, layoutParams1.bottomMargin);
        mViewPager.setLayoutParams(layoutParams1);
    }

    private void init() {
        mNestedScrollingChildHelper = new NestedScrollingChildHelper(this);
        mNestedScrollingParentHelper = new NestedScrollingParentHelper(this);
        fragmentHander = new FragmentHander();
        mViewPager = new ViewPager2(getContext());
        mViewPager.setOffscreenPageLimit(5);
        int marginLeft1 = DisplayUtil.dip2px(getContext(), marginLeft);
        int marginRight1 = DisplayUtil.dip2px(getContext(), marginRight);
        LayoutParams layoutParams1 = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        layoutParams1.setMargins(marginLeft1, 0, marginRight1, 0);
        addView(mViewPager, layoutParams1);

        mBannerCursorView = new BannerCursorView2(getContext());
        LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 80);
        layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER;
        addView((View) mBannerCursorView, layoutParams);

        adsResourceList = new ArrayList<>();
        indicatorCount = adsResourceList.size();
        mBannerCursorView.setIndicatorCount(indicatorCount);
        if (adsAdapter == null) {
            adsAdapter = new BannerFragmentStateAdapter((FragmentActivity) getContext(), claszz, adsResourceList, fragmentHander, () -> setCurrentItem(mViewPager.getCurrentItem() + 1));
        }
        //mViewPager.setPageMargin(getResources().getInteger(R.integer.viewpager_margin_width));
        //mViewPager.setPageMarginDrawable(R.drawable.viewpager_margin);
        mViewPager.setAdapter(adsAdapter);
        setCurrentItem(adsAdapter.firstFragmentPosition, false);
        mViewPager.unregisterOnPageChangeCallback(mOnPageChangeCallback);
        mViewPager.registerOnPageChangeCallback(mOnPageChangeCallback);
        postDelayedToNext(loopTime);
        mViewPager.setClipChildren(false); //VP的内容可以不在限制内绘制
        initScroller();
        //requestDisallowInterceptTouchEvent(true);
        setNestedScrollingEnabled(true);
    }

    ViewPager2.OnPageChangeCallback onPageChangeCallback2;

    public void setOnPageChangeCallback(ViewPager2.OnPageChangeCallback onPageChangeCallback) {
        this.onPageChangeCallback2 = onPageChangeCallback;
    }

    ViewPager2.OnPageChangeCallback mOnPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);
            //QdLog.i("mViewPager","当前页面："+position);
            if (currentPosition != position && mBannerCursorView != null) {
                selectIndex = adsAdapter.getDataPosition(position);
                fragmentHander.setCurrentItem(selectIndex);
                mBannerCursorView.selecte(selectIndex);
                //mBannerCursorView.setIndicatorCount(indicatorCount);
            }
            currentPosition = position;
            if (onPageChangeCallback2 != null) {
                onPageChangeCallback2.onPageScrolled(adsAdapter.getDataPosition(currentPosition), positionOffset, positionOffsetPixels);
            }
            resetDelayedTime();
        }

        @Override
        public void onPageSelected(int position) {
            currentPosition = position;
            resetDelayedTime();
            //QdLog.i("mViewPager","onPageSelected="+position);
            super.onPageSelected(position);
            selectIndex = adsAdapter.getDataPosition(position);
            fragmentHander.setCurrentItem(selectIndex);
            if (mBannerCursorView != null) {
                //QdLog.i("selectIndex","selectIndex="+selectIndex);
                mBannerCursorView.selecte(selectIndex);
                mBannerCursorView.setIndicatorCount(indicatorCount);
            }
            if (onPageChangeCallback2 != null) {
                onPageChangeCallback2.onPageSelected(selectIndex);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            //QdLog.i("mViewPager","onPageScrollStateChanged state="+state);
            super.onPageScrollStateChanged(state);
            resetDelayedTime();
            if (state == 0) {
                //QdLog.i("mViewPager","fragment切换完成："+currentPosition);
                //QdLog.d("onPageScrollStateChanged item="+mViewPager.getCurrentItem()+"<===>"+adsAdapter.getDataPosition(mViewPager.getCurrentItem()));
                if (Math.abs(adsAdapter.getRelativePosition(mViewPager.getCurrentItem())) > adsAdapter.getItemCount2()) {
                    mViewPager.setCurrentItem(adsAdapter.getDataPosition(mViewPager.getCurrentItem()) + adsAdapter.getFirstFragmentPosition(), false);
                }
                fragmentHander.setCurrentItem(adsAdapter.getDataPosition(mViewPager.getCurrentItem()));
            }
        }
    };

    public void setCurrentItem(int position) {
        int basePosition = adsAdapter.getFirstFragmentPosition();
        setCurrentRealItem(basePosition + position, true);
    }

    public void setCurrentItem(int position, boolean smoothScroll) {
        int basePosition = adsAdapter.getFirstFragmentPosition();
        setCurrentRealItem(basePosition + position, smoothScroll);
    }

    public void setCurrentRealItem(int position, boolean smoothScroll) {
        fragmentHander.setCurrentItem(position);
        mViewPager.setCurrentItem(position, smoothScroll);
    }

    List<AdsResource> adsResourceList = new ArrayList<>();

    public void setData(List<AdsResource> list) {
        indicatorCount = list.size();
        if (mBannerCursorView != null) {
            mBannerCursorView.setIndicatorCount(indicatorCount <= 1 ? 0 : indicatorCount);
        }
        adsResourceList.clear();
        if (adsAdapter != null) {
            adsAdapter.notifyDataSetChanged();
        }
        adsResourceList.addAll(list);
        if (adsAdapter != null) {
            //setOffscreenPageLimit(list.size() > 1 ? 3 : 1);
            adsAdapter.setData(list);
            setCurrentItem(adsAdapter.getFirstFragmentPosition(), false);
        }
        postDelayedToNext(loopTime);
    }

    public void initScroller() {
        RecyclerView recyclerView = (RecyclerView) mViewPager.getChildAt(0);
        recyclerView.setClipChildren(false);
        recyclerView.setOnTouchListener(null);
        recyclerView.setOnClickListener(null);
        recyclerView.setClickable(false);
        recyclerView.setEnabled(false);

        mViewPager.setOnTouchListener(null);
        mViewPager.setOnClickListener(null);
        mViewPager.setClickable(false);
        mViewPager.setEnabled(false);
    }

    boolean canDrag = true;

    /**
     * 设置是否可以触摸拖动
     *
     * @param canDrag
     */
    public void setCanDrag(boolean canDrag) {
        this.canDrag = canDrag;
        //setOnTouchListener(null);
        //setOnClickListener(null);
        setClickable(canDrag);
        setEnabled(canDrag);
    }

    int mActivePointerId;

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (!canDrag || adsResourceList == null || adsResourceList.size() <= 0) {
            return true;
        } else {
// Check if the pointer index is valid
            int pointerIndex = ev.getActionIndex();
            //QdLog.i(TAG,"onInterceptTouchEvent1 getAction="+ev.getAction()+",RawY="+ev.getRawY()+",pointerIndex="+pointerIndex+",PointerCount="+ev.getPointerCount());
            if (pointerIndex < 0 || pointerIndex >= ev.getPointerCount()) {
                return false;
            }
            if (ev.getPointerCount() > 1) {//禁用多指滚动
                //QdLog.d("onInterceptTouchEvent 禁用多指滚动："+ev.getPointerCount());
                return true;
            }
            // return super.onInterceptTouchEvent(ev);
            return false;
        }
    }

    float startX;
    float startY;

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //QdLog.i(TAG,"dispatchTouchEvent getAction="+ev.getAction());
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = ev.getX();
                startY = ev.getRawY();
                if (ev.getPointerCount() > 1) {//禁用多指滚动
                    QdLog.d("禁用多指滚动：" + ev.getPointerCount());
                    return false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
//                final int pointerIndex = ev.findPointerIndex(mActivePointerId);
//                if (pointerIndex < 0) {
//                    // Invalid pointer index
//                    return false;
//                }
                if (ev.getPointerCount() > 1) {//禁用多指滚动
                    //QdLog.d("禁用多指滚动："+ev.getPointerCount());
                    return false;
                }

                float x2 = ev.getX();
                float y2 = ev.getRawY();
                if (Math.abs(startX - x2) > Math.abs(startY - y2)) {
                    if (startX - x2 > 1) {//右滑
                        requestDisallowInterceptTouchEvent(true);
                    } else if (x2 - startX > 1) {//左滑
                        requestDisallowInterceptTouchEvent(true);
                    }
                } else if (Math.abs(startY - y2) > 200) {
                    if (startY - y2 > 100) {
                        requestDisallowInterceptTouchEvent(false);
                    } else if (y2 - startY > 100) {
                        requestDisallowInterceptTouchEvent(false);
                    }
                }
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        QdLog.i(TAG, "onTouchEvent getAction=" + event.getAction() + event.getRawY());
        return super.onTouchEvent(event);
    }

    private void resetDelayedTime() {
        postDelayedToNext(loopTime);
    }

    /**
     * 延迟滚动到下一个
     *
     * @param time
     */
    public void postDelayedToNext(long time) {
        handler.removeCallbacks(runnable);
        handler.postDelayed(runnable, Math.min(time, loopTime));
    }

    public void removePostDelayed() {
        if (handler != null && runnable != null) {
            handler.removeCallbacks(runnable);
        }
    }

    /**
     * 根据广告类型动态调整
     * 1video播放完成时切换下一个
     * 2video播放超时后切换下一个
     * <p>
     * 图片
     * 根据固定时长切换
     */
    long loopTime = 10000;

    public void setLoopTime(long loopTime) {
        this.loopTime = loopTime;
    }

    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            if (adsResourceList == null || adsResourceList.size() <= 1) {
                return;
            }

            handler.removeCallbacks(runnable);
            int index = adsAdapter.getDataPosition(mViewPager.getCurrentItem());
            int to = (index + 1) % adsAdapter.getItemCount2();
            AdsResource adsResource = adsResourceList.get(index);
            if (adsResource.getType() == BannerContentType.video.value()) {
                setCurrentItem(to);
                handler.postDelayed(runnable, loopTime);
            } else {
                setCurrentItem(to);
                handler.postDelayed(runnable, loopTime);
            }
        }
    };

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        postDelayedToNext(loopTime);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        handler.removeCallbacks(runnable);
    }

    /**
     * 设置切换效果
     *
     * @param b
     * @param transformer
     */
    public void setPageTransformer(boolean b, ViewPager2.PageTransformer transformer) {
        mViewPager.setPageTransformer(transformer);
    }

    /**
     * 设置画廊内边距
     *
     * @param
     */
    public void setGalleryPadding(int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
        RecyclerView recyclerView = (RecyclerView) mViewPager.getChildAt(0);
        recyclerView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
        recyclerView.setClipToPadding(false);
    }

    public void setOffscreenPageLimit(int i) {
        mViewPager.setOffscreenPageLimit(i);
    }

    boolean showLoadingView = true;

    @Override
    public void setClipChildren(boolean clipChildren) {
        super.setClipChildren(clipChildren);
        mViewPager.setClipChildren(false);
    }

    public void showLoadingView(boolean show) {
        this.showLoadingView = show;
        //postInvalidate();
    }

    public void setOrientation(int orientation) {
        mViewPager.setOrientation(orientation);//ViewPager2.ORIENTATION_HORIZONTAL
    }

    public interface BannerIndicator {
        void selecte(int position);

        void setIndicatorCount(int count);
    }


    /********  NestedScrollingParent1 start  *********/
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, @ViewCompat.ScrollAxis int axes) {
//        return isEnabled() && !mReturningToStart && !mRefreshing
//                && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
        boolean b = isEnabled() && (axes & ViewCompat.SCROLL_AXIS_HORIZONTAL) != 0;
        //QdLog.i(TAG, "onStartNestedScroll b=" + b);
        //requestDisallowInterceptTouchEvent(true);
        return true;
    }

    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, @ViewCompat.ScrollAxis int axes) {
        //mNestedScrollingParentHelper.onNestedScrollAccepted(child, target, axes);
    }

    public void onStopNestedScroll(@NonNull View target) {
        mNestedScrollingParentHelper.onStopNestedScroll(target);
        // Finish the spinner for nested scrolling if we ever consumed any
        // unconsumed nested scroll
        // Dispatch up our nested parent
        stopNestedScroll();
    }

    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed,
                               int dxUnconsumed, int dyUnconsumed) {
        onNestedScroll(target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
                ViewCompat.TYPE_TOUCH, mNestedScrollingV2ConsumedCompat);
    }

    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed) {
        consumed[0] = -Math.abs(dx);
        consumed[1] = -Math.abs(dy);
    }

    public boolean onNestedFling(@NonNull View target, float velocityX, float velocityY, boolean consumed) {
        return dispatchNestedFling(velocityX, velocityY, consumed);
    }

    public boolean onNestedPreFling(@NonNull View target, float velocityX, float velocityY) {
        return dispatchNestedPreFling(velocityX, velocityY);
    }

    public int getNestedScrollAxes() {
        return mNestedScrollingParentHelper.getNestedScrollAxes();
    }
    /********  NestedScrollingParent1 end  *********/

    /********** NestedScrollingParent2 start ***********/

    @Override
    public boolean onStartNestedScroll(@NonNull View child, @NonNull View target, int axes, int type) {
        if (type == ViewCompat.TYPE_TOUCH) {
            return onStartNestedScroll(child, target, axes);
        } else {
            return false;
        }
    }

    @Override
    public void onNestedScrollAccepted(@NonNull View child, @NonNull View target, int axes, int type) {

    }

    @Override
    public void onStopNestedScroll(@NonNull View target, int type) {

    }

    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {

    }

    @Override
    public void onNestedPreScroll(@NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) {

    }
    /********** NestedScrollingParent2 end ***********/


    /********* NestedScrollingChild2 start ************/
    @Override
    public boolean startNestedScroll(int axes, int type) {
        return type == ViewCompat.TYPE_TOUCH && startNestedScroll(axes);
    }

    @Override
    public void stopNestedScroll(int type) {
        if (type == ViewCompat.TYPE_TOUCH) {
            stopNestedScroll();
        }
    }

    @Override
    public boolean hasNestedScrollingParent(int type) {
        return type == ViewCompat.TYPE_TOUCH && hasNestedScrollingParent();
    }

    @Override
    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type) {
        return type == ViewCompat.TYPE_TOUCH && mNestedScrollingChildHelper.dispatchNestedScroll(
                dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow, type);
    }

    @Override
    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed, @Nullable int[] offsetInWindow, int type) {
        return type == ViewCompat.TYPE_TOUCH && dispatchNestedPreScroll(dx, dy, consumed,
                offsetInWindow);
    }
    /********* NestedScrollingChild2 end ************/

    /********  NestedScrollingChild3 start  *********/
    @Override
    public void dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow, int type, @NonNull int[] consumed) {

    }
    /********  NestedScrollingChild3 end  *********/

    /********  NestedScrollingParent3 start  *********/
    @Override
    public void onNestedScroll(@NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, @NonNull int[] consumed) {

    }
    /********  NestedScrollingParent3 end  *********/
}
